package com.damai.action.aop.impl;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.citywithincity.api.ApiConfig;
import com.citywithincity.utils.CachedClassUtil;
import com.citywithincity.utils.ClassUtil;
import com.damai.action.aop.Interceptor;
import com.damai.action.aop.InterceptorInit;
import com.damai.action.aop.Invoker;
import com.damai.action.aop.InvokerFactory;
import com.damai.annotation.Aop;

public class InvokerFactoryImpl implements InvokerFactory {

	public static final InvokerFactory DEFAULT = new InvokerFactoryImpl();

	private InvokerFactoryImpl() {

	}

	public List<Class<?>> getAnnotationClasses(Class<?> controllerClass, Method method) {
		List<Class<?>> list = new ArrayList<Class<?>>(5);
		Aop before = controllerClass.getAnnotation(Aop.class);
		if (before != null) {
			for (Class<?> clazz : before.value()) {
				if (!list.contains(clazz)) {
					list.add(clazz);
				}
			}
		}
		before = method.getAnnotation(Aop.class);
		if (before != null) {
			for (Class<?> clazz : before.value()) {
				if (!list.contains(clazz)) {
					list.add(clazz);
				}
			}
		}
		return list;
	}

	private Map<Class<?>, Interceptor> cache = new ConcurrentHashMap<Class<?>, Interceptor>();

	private Interceptor getInterceptor(Class<?> clazz, Method method) {
		Interceptor result = null;
		/**
		 * 如果可以初始化，说明每一次都会是新的
		 */
		if (ClassUtil.hasInterface(clazz, InterceptorInit.class)) {
			try {
				result = (Interceptor) clazz.newInstance();
			} catch (Exception e) {
				ApiConfig.error("初始化" + clazz.getName() + "错误", e);
				throw new RuntimeException(e);
			}
			((InterceptorInit) result).init(clazz, method);
			return result;
		}

		result = cache.get(clazz);
		if (result == null) {
			try {
				result = (Interceptor) clazz.newInstance();
			} catch (Exception e) {
				ApiConfig.error("初始化" + clazz.getName() + "错误", e);
				throw new RuntimeException(e);
			}
			cache.put(clazz, result);
		}
		return result;
	}

	@Override
	public Invoker createInvoker(Class<?> controllerClass, Method method, List<Interceptor> interceptors) {
		Invoker invoker = createInvoker(controllerClass, method);
		for (Interceptor interceptor : interceptors) {
			invoker = new InvokerChain(interceptor, invoker);
		}
		return invoker;
	}

	private Invoker createInvoker(Class<?> controllerClass, Method method) {
		List<Class<?>> classes = getAnnotationClasses(controllerClass, method);

		Object controller = CachedClassUtil.newController(controllerClass);
		MethodInvoker invokerImpl = new MethodInvoker(controller, method);
		if (classes.size() == 0) {
			return invokerImpl;
		}

		Invoker invoker = invokerImpl;

		for (int i = classes.size() - 1; i >= 0; --i) {
			Class<?> clazz = classes.get(i);
			invoker = new InvokerChain(getInterceptor(clazz, method), invoker);
		}

		return invoker;
	}

}
